#include <QtCore>
#include <QFile>
#include <QTextStream>
#include <QRegularExpression>

#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>

#define LOG_FILE_NAME           "rh530.log"
#define LOG_BACKUP_FILE_NAME    "old_rh530.log"
#define LOG_FILE_MAX_SIZE       (100 * 1024 * 1024)

#define COLOR_NORMAL        "\x1B[0m"
#define COLOR_FG_BLACK      "\x1B[30m"
#define COLOR_FG_RED        "\x1B[31m"
#define COLOR_FG_GREEN      "\x1B[32m"
#define COLOR_FG_YELLOW     "\x1B[33m"
#define COLOR_FG_BLUE       "\x1B[34m"
#define COLOR_FG_MAGENTA    "\x1B[35m"
#define COLOR_FG_CYAN       "\x1B[36m"
#define COLOR_FG_LGRAY      "\x1B[37m"
#define COLOR_FG_DGRAY      "\x1B[90m"
#define COLOR_FG_LRED       "\x1B[91m"
#define COLOR_FG_LGREEN     "\x1B[92m"
#define COLOR_FG_LYELLOW    "\x1B[93m"
#define COLOR_FG_LBLUE      "\x1B[94m"
#define COLOR_FG_LMAGENTA   "\x1B[95m"
#define COLOR_FG_LCYAN      "\x1B[96m"
#define COLOR_FG_WHITE      "\x1B[97m"

//#define COLOR_NORMAL        ""
//#define COLOR_FG_BLACK      ""
//#define COLOR_FG_RED        ""
//#define COLOR_FG_GREEN      ""
//#define COLOR_FG_YELLOW     ""
//#define COLOR_FG_BLUE       ""
//#define COLOR_FG_MAGENTA    ""
//#define COLOR_FG_CYAN       ""
//#define COLOR_FG_LGRAY      ""
//#define COLOR_FG_DGRAY      ""
//#define COLOR_FG_LRED       ""
//#define COLOR_FG_LGREEN     ""
//#define COLOR_FG_LYELLOW    ""
//#define COLOR_FG_LBLUE      ""
//#define COLOR_FG_LMAGENTA   ""
//#define COLOR_FG_LCYAN      ""
//#define COLOR_FG_WHITE      ""

void MessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
    QString timeStr = QDateTime::currentDateTime().toString("yyyy.MM.dd hh:mm:ss");
    QByteArray localMsg = msg.toLocal8Bit();
    char *s = new char[localMsg.length() + 1024];
    if (s == nullptr)
        return;

    const char *file = context.file ? context.file : "";
    const char *function = context.function ? context.function : "";

    switch (type) {
    case QtDebugMsg:
        sprintf(s, "%s[%s] %sDebug%s: %s (%s:%u, %s)\n",
                COLOR_FG_GREEN, timeStr.toLocal8Bit().constData(),
                COLOR_FG_BLUE, COLOR_NORMAL,
                localMsg.constData(), file, context.line, function);
        break;
    case QtInfoMsg:
        sprintf(s, "%s[%s] %sInfo%s: %s\n",
                COLOR_FG_GREEN, timeStr.toLocal8Bit().constData(),
                COLOR_FG_BLUE, COLOR_NORMAL,
                localMsg.constData());
        break;
    case QtWarningMsg:
        sprintf(s, "[%s] Warning: %s\n", timeStr.toLocal8Bit().constData(), localMsg.constData());
        break;
    case QtCriticalMsg:
        sprintf(s, "[%s] Critical: %s (%s:%u, %s)\n", timeStr.toLocal8Bit().constData(), localMsg.constData(), file, context.line, function);
        break;
    case QtFatalMsg:
        sprintf(s, "[%s] Fatal: %s (%s:%u, %s)\n", timeStr.toLocal8Bit().constData(), localMsg.constData(), file, context.line, function);
        break;
    }

    fprintf(stderr, "%s", s);

    QFile logFile(LOG_FILE_NAME);
    if (logFile.open(QIODevice::Text | QIODevice::Append)) {
        logFile.write(s);
        if (logFile.size() > LOG_FILE_MAX_SIZE) {
            logFile.close();
            QFile::remove(LOG_BACKUP_FILE_NAME);
            QFile::copy(LOG_FILE_NAME, LOG_BACKUP_FILE_NAME);
            QFile::remove(LOG_FILE_NAME);
        }
        else
            logFile.close();
    }

    delete[] s;
}

bool FilterLogMessage(QDateTime from, QDateTime to)
{
    QFile tmpLogFile("/tmp/" + QString(LOG_FILE_NAME));
    if (!tmpLogFile.open(QIODevice::Text | QIODevice::WriteOnly))
        return false;
    QTextStream tmpLogStream(&tmpLogFile);
    QFile logFile(LOG_FILE_NAME);
    if (logFile.open(QIODevice::Text | QIODevice::ReadOnly)) {
        QTextStream logStream(&logFile);
        QString logMsg;
        QRegularExpression  re(".*\\[(.*)\\].*(Debug|Info|Warning|Critical|Fatal).*\\:(.*)");
        while (logStream.readLineInto(&logMsg)) {
            QRegularExpressionMatch match = re.match(&logMsg);
            if (match.hasMatch()) {
                QDateTime msgDate = QDateTime::fromString(match.captured(1), "yyyy.MM.dd hh:mm:ss");
                if (!msgDate.isValid() || msgDate < from)
                    continue;
                if (msgDate > to)
                    break;
                QString msgOut = "[" + match.captured(1) + "]"+ match.captured(2) + ":" + match.captured(3);
                tmpLogStream << msgOut << Qt::endl;
            }
        }
    }

    return true;
}
